package com.hjt.gulimall.ware.service.impl;

import com.alibaba.fastjson.TypeReference;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.hjt.common.constant.OrderConstant;
import com.hjt.common.exception.NoStockException;
import com.hjt.common.to.mq.StockLockedTo;
import com.hjt.common.to.order.OrderTo;
import com.hjt.common.to.order.SkuLockTo;
import com.hjt.common.to.order.WareLockTo;
import com.hjt.common.to.ware.SkuHasStockTo;
import com.hjt.common.to.ware.SkuInfoTo;
import com.hjt.common.utils.PageUtils;
import com.hjt.common.utils.Query;
import com.hjt.common.utils.R;
import com.hjt.gulimall.ware.constant.RabbitMqConstant;
import com.hjt.gulimall.ware.constant.WareConstant;
import com.hjt.gulimall.ware.dao.WareSkuDao;
import com.hjt.gulimall.ware.entity.WareOrderTaskDetailEntity;
import com.hjt.gulimall.ware.entity.WareOrderTaskEntity;
import com.hjt.gulimall.ware.entity.WareSkuEntity;
import com.hjt.gulimall.ware.feign.OrderFeignService;
import com.hjt.gulimall.ware.feign.ProductFeign;
import com.hjt.gulimall.ware.service.WareOrderTaskDetailService;
import com.hjt.gulimall.ware.service.WareOrderTaskService;
import com.hjt.gulimall.ware.service.WareSkuService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;



@Service("wareSkuService")
@Slf4j
public class WareSkuServiceImpl extends ServiceImpl<WareSkuDao, WareSkuEntity> implements WareSkuService {

    @Autowired
    private ProductFeign productFeign;

    @Autowired
    private RabbitTemplate rabbitTemplate;

    @Autowired
    private WareOrderTaskDetailService orderTaskDetailService;

    @Autowired
    private WareOrderTaskService orderTaskService;

    @Autowired
    private OrderFeignService orderFeignService;

    @Override
    public PageUtils queryPage(Map<String, Object> params) {
        IPage<WareSkuEntity> page = this.page(
                new Query<WareSkuEntity>().getPage(params),
                new QueryWrapper<WareSkuEntity>()
        );

        return new PageUtils(page);
    }

    /**
     * 条件分页查询
     * @param params
     * @return
     */
    @Override
    public PageUtils queryPageWithCondition(Map<String, Object> params) {
        // 封装查询条件
        QueryWrapper<WareSkuEntity> wrapper = new QueryWrapper<>();
        String wareId = (String) params.get("wareId");
        if (StringUtils.hasLength(wareId)) {
            wrapper.eq("ware_id",wareId);
        }
        String skuId = (String) params.get("skuId");
        if (StringUtils.hasLength(skuId)) {
            wrapper.eq("sku_id",skuId);
        }
        IPage<WareSkuEntity> page = this.page(
                new Query<WareSkuEntity>().getPage(params),
                wrapper
        );

        return new PageUtils(page);
    }

    /**
     * sku入库
     * @param skuId sku的id
     * @param wareId 仓库的id
     * @param skuNum sku的数量
     */
    @Override
    @Transactional
    public void addStock(Long skuId, Long wareId, Integer skuNum) {
        // 判断是否库存中已有这个商品
        QueryWrapper<WareSkuEntity> wrapper = new QueryWrapper<WareSkuEntity>().eq("sku_id", skuId).eq("ware_id", wareId);

        // 不存在则新建
        if (baseMapper.selectCount(wrapper) ==0 ){
            WareSkuEntity wareSkuEntity = new WareSkuEntity();
            wareSkuEntity.setSkuId(skuId);
            wareSkuEntity.setStock(skuNum);
            wareSkuEntity.setWareId(wareId);
            wareSkuEntity.setStockLocked(0);
            // 设置商品名称
            try {
                SkuInfoTo skuInfo = productFeign.info(skuId);
                if (skuInfo != null) {
                    wareSkuEntity.setSkuName(skuInfo.getSkuName());
                }
            } catch (Exception e) {
                log.warn("错误"+e);
            }
            baseMapper.insert(wareSkuEntity);
        } else {
            // 存在则新增产品数量
            baseMapper.addStock(skuId, wareId,skuNum);
        }

    }

    @Override
    public List<SkuHasStockTo> querySkuHasStock(List<Long> skuIdList) {
        return baseMapper.querySkuHasStockBySkuIds(skuIdList);
    }

    /**
     * 锁定某个商品的库存
     *
     *
     *
     *
     * @param wareLockTo
     * @return
     */
    @Override
    @Transactional
    public boolean lock(WareLockTo wareLockTo) {
        // 保存库存工作单详情，溯源
        WareOrderTaskEntity wareOrderTaskEntity = new WareOrderTaskEntity();
        wareOrderTaskEntity.setOrderSn(wareLockTo.getOrderSn());
        orderTaskService.save(wareOrderTaskEntity);
        // 1.找到商品在哪个仓库有库存，然后锁库存
        List<SkuLockTo> itemList = wareLockTo.getItemList();
        StockLockedTo stockLockedTo = new StockLockedTo();
        stockLockedTo.setOrderTaskId(wareOrderTaskEntity.getId());
        stockLockedTo.setOrderTaskDetailIdList(new ArrayList<>(itemList.size()));
        for (SkuLockTo lockTo : itemList) {
            Long skuId = lockTo.getSkuId();
            // 找出一个有库存的仓库
            // TODO:锁定库存
            Long wareId = baseMapper.selectHasStockedWareId(skuId, lockTo.getNums());
            if (wareId == null) {
                throw new NoStockException(skuId);
            }
            int lock = baseMapper.lock(skuId, lockTo.getNums(), wareId);
            // 锁定库存失败
            if (lock != 1) {
                throw new NoStockException(skuId);
            } else {
                // 锁定库存成功 TODO：告诉库存锁定成功
                WareOrderTaskDetailEntity taskDetailEntity = new WareOrderTaskDetailEntity(null,skuId,"",
                        lockTo.getNums(),wareOrderTaskEntity.getId(), wareId, WareConstant.LOCK_STATUS_LOCKED);
                orderTaskDetailService.save(taskDetailEntity);
                stockLockedTo.getOrderTaskDetailIdList().add(taskDetailEntity.getId());
            }
        }
        // 所有商品锁定库存成功，发送锁定任务消息
        rabbitTemplate.convertAndSend(RabbitMqConstant.STOCK_EVENT_EXCHANGE_NAME, RabbitMqConstant.STOCK_LOCK_ROUTE_KEY, stockLockedTo);
        return true;
    }


    @Override
    public void unlock(StockLockedTo lockedTo) {
        Long orderTaskId = lockedTo.getOrderTaskId();
        // 判断订单是否存在
        WareOrderTaskEntity orderTaskEntity = orderTaskService.getById(orderTaskId);
        String orderSn = orderTaskEntity.getOrderSn();
        R r = orderFeignService.getOrderByOrderSn(orderSn);
        // 远程调用失败
        if (r == null || r.getCode() != 0) {
            throw new RuntimeException("远程调用订单服务失败");
        } else {
            OrderTo orderTo = r.getData(new TypeReference<OrderTo>() {});
            // 1）订单不存在，解锁库存 2）判断订单状态 已取消：解锁库存
            if (orderTo == null || orderTo.getStatus().equals(OrderConstant.ORDER_STATUS_CLOSED)) {
                unlockStock(lockedTo);
            }
        }
    }

    /**
     * 订单释放后，解锁库存，防止订单消息卡顿，导致库存解锁消息到期时，订单关闭消息还没到期，从而库存无法解锁
     * @param orderTo
     */
    @Override
    @Transactional
    public void unlock(com.hjt.common.to.mq.OrderTo orderTo) {
        // 根据订单号，找到库存工作单
        String orderSn = orderTo.getOrderSn();
        // 根据库存操作单，判断库存是否解锁过
        WareOrderTaskEntity task = orderTaskService.getByOrderSn(orderSn);
        Long taskId = task.getId();
        // 根据库存操作id，找到所有的锁定的库存操作详情
        List<WareOrderTaskDetailEntity> taskDetailList = orderTaskDetailService.list(new QueryWrapper<WareOrderTaskDetailEntity>()
                .eq("task_id", taskId)
                .eq("lock_status", WareConstant.LOCK_STATUS_LOCKED));

        // 解锁库存
        for (WareOrderTaskDetailEntity taskDetailEntity : taskDetailList) {
            unlockStock(taskDetailEntity);
        }
    }

    private void unlockStock(StockLockedTo lockedTo) {
        //获取 所有订单任务详情
        Collection<WareOrderTaskDetailEntity> taskDetailList = orderTaskDetailService.listByIds(lockedTo.getOrderTaskDetailIdList());
        if (!CollectionUtils.isEmpty(taskDetailList)) {
            for (WareOrderTaskDetailEntity taskDetail : taskDetailList) {
                // 库存没有处于锁定状态，才需要解锁
                if (taskDetail.getLockStatus().equals(WareConstant.LOCK_STATUS_LOCKED)) {
                    unlockStock(taskDetail); // 解锁库存
                }
            }
        }
    }

    // 解锁库存
    private void unlockStock(WareOrderTaskDetailEntity taskDetail) {
        baseMapper.unlock(taskDetail.getSkuId(), taskDetail.getSkuNum(), taskDetail.getWareId());
        // 更新库存工作单状态(已解锁)
        taskDetail.setLockStatus(WareConstant.LOCK_STATUS_UNLOCKED);
        orderTaskDetailService.updateById(taskDetail);
    }
}